using System;
using System.Collections.Generic;
using UnityEngine;
using Newtonsoft.Json;

namespace GenerativeAgents.Core
{
    /// <summary>
    /// 可序列化的记忆节点
    /// </summary>
    [System.Serializable]
    public class SerializableMemoryNode
    {
        public string nodeId;
        public MemoryType type;
        public string content;
        public string description;
        public float[] embedding;
        public List<string> keywords;
        public string subject;
        public string predicate;
        public string objectEntity;
        public DateTime createdTime;
        public DateTime lastAccessTime;
        public SerializableVector3 location;
        public string locationName;
        public int poignancy;
        public int accessCount;
        public float decayFactor;
        public List<string> relatedNodeIds;
        public List<string> participants;
        public string sourceEventId;
        public Dictionary<string, object> metadata;
        public bool isExpired;
        public DateTime expirationTime;
        
        public SerializableMemoryNode() { }
        
        public SerializableMemoryNode(MemoryNode memoryNode)
        {
            nodeId = memoryNode.nodeId;
            type = memoryNode.type;
            content = memoryNode.content;
            description = memoryNode.description;
            embedding = memoryNode.embedding;
            keywords = new List<string>(memoryNode.keywords ?? new List<string>());
            subject = memoryNode.subject;
            predicate = memoryNode.predicate;
            objectEntity = memoryNode.objectEntity;
            createdTime = memoryNode.createdTime;
            lastAccessTime = memoryNode.lastAccessTime;
            location = new SerializableVector3(memoryNode.location);
            locationName = memoryNode.locationName;
            poignancy = memoryNode.poignancy;
            accessCount = memoryNode.accessCount;
            decayFactor = memoryNode.decayFactor;
            relatedNodeIds = new List<string>(memoryNode.relatedNodeIds ?? new List<string>());
            participants = new List<string>(memoryNode.participants ?? new List<string>());
            sourceEventId = memoryNode.sourceEventId;
            metadata = new Dictionary<string, object>(memoryNode.metadata ?? new Dictionary<string, object>());
            isExpired = memoryNode.isExpired;
            expirationTime = memoryNode.expirationTime;
        }
        
        public MemoryNode ToMemoryNode()
        {
            var memoryNode = new MemoryNode
            {
                nodeId = nodeId,
                type = type,
                content = content,
                description = description,
                embedding = embedding,
                keywords = keywords ?? new List<string>(),
                subject = subject,
                predicate = predicate,
                objectEntity = objectEntity,
                createdTime = createdTime,
                lastAccessTime = lastAccessTime,
                location = location?.ToVector3() ?? Vector3.zero,
                locationName = locationName,
                poignancy = poignancy,
                accessCount = accessCount,
                decayFactor = decayFactor,
                relatedNodeIds = relatedNodeIds ?? new List<string>(),
                participants = participants ?? new List<string>(),
                sourceEventId = sourceEventId,
                metadata = metadata ?? new Dictionary<string, object>(),
                isExpired = isExpired,
                expirationTime = expirationTime
            };
            
            return memoryNode;
        }
    }
    
    /// <summary>
    /// 可序列化的空间记忆
    /// </summary>
    [System.Serializable]
    public class SerializableSpatialMemory
    {
        public SerializableSpatialNode rootNode;
        public Dictionary<string, SerializableVector3> agentLocations;
        public Dictionary<string, SerializableVector3> objectLocations;
        public Dictionary<string, DateTime> lastUpdateTimes;
        
        public SerializableSpatialMemory() { }
        
        public SerializableSpatialMemory(SpatialMemory spatialMemory)
        {
            if (spatialMemory != null)
            {
                rootNode = new SerializableSpatialNode(spatialMemory.GetRootNode());
                
                agentLocations = new Dictionary<string, SerializableVector3>();
                objectLocations = new Dictionary<string, SerializableVector3>();
                lastUpdateTimes = new Dictionary<string, DateTime>();
                
                // 获取智能体位置（简化实现）
                var allNodes = spatialMemory.GetAllSpatialNodes();
                foreach (var node in allNodes.Values)
                {
                    foreach (var agent in node.agents)
                    {
                        if (!agentLocations.ContainsKey(agent))
                        {
                            agentLocations[agent] = new SerializableVector3(node.position);
                            lastUpdateTimes[agent] = DateTime.Now;
                        }
                    }
                    
                    foreach (var obj in node.objects)
                    {
                        if (!objectLocations.ContainsKey(obj))
                        {
                            objectLocations[obj] = new SerializableVector3(node.position);
                            lastUpdateTimes[obj] = DateTime.Now;
                        }
                    }
                }
            }
        }
        
        public void RestoreTo(SpatialMemory spatialMemory)
        {
            if (spatialMemory == null || rootNode == null) return;
            
            // 重建空间结构（简化实现）
            // 在实际项目中需要完整重建空间树
            
            // 恢复智能体和对象位置
            foreach (var agentLocation in agentLocations)
            {
                var position = agentLocation.Value.ToVector3();
                spatialMemory.UpdateAgentLocation(agentLocation.Key, "restored_location", position);
            }
            
            foreach (var objectLocation in objectLocations)
            {
                var position = objectLocation.Value.ToVector3();
                spatialMemory.UpdateObjectLocation(objectLocation.Key, "restored_location", position);
            }
        }
    }
    
    /// <summary>
    /// 可序列化的空间节点
    /// </summary>
    [System.Serializable]
    public class SerializableSpatialNode
    {
        public string name;
        public string description;
        public SerializableVector3 position;
        public SerializableVector3 bounds;
        public SerializableQuaternion rotation;
        public int depth;
        public List<string> objects;
        public List<string> agents;
        public List<string> features;
        public List<SerializableVector3> waypoints;
        public bool isAccessible;
        public float movementCost;
        public SpatialType spatialType;
        public Dictionary<string, object> properties;
        public List<string> tags;
        public Dictionary<string, SerializableSpatialNode> children;
        
        public SerializableSpatialNode() { }
        
        public SerializableSpatialNode(SpatialNode spatialNode)
        {
            if (spatialNode != null)
            {
                name = spatialNode.name;
                description = spatialNode.description;
                position = new SerializableVector3(spatialNode.position);
                bounds = new SerializableVector3(spatialNode.bounds);
                rotation = new SerializableQuaternion(spatialNode.rotation);
                depth = spatialNode.depth;
                objects = new List<string>(spatialNode.objects ?? new List<string>());
                agents = new List<string>(spatialNode.agents ?? new List<string>());
                features = new List<string>(spatialNode.features ?? new List<string>());
                waypoints = spatialNode.waypoints?.Select(w => new SerializableVector3(w)).ToList() ?? new List<SerializableVector3>();
                isAccessible = spatialNode.isAccessible;
                movementCost = spatialNode.movementCost;
                spatialType = spatialNode.spatialType;
                properties = new Dictionary<string, object>(spatialNode.properties ?? new Dictionary<string, object>());
                tags = new List<string>(spatialNode.tags ?? new List<string>());
                
                // 序列化子节点
                children = new Dictionary<string, SerializableSpatialNode>();
                if (spatialNode.children != null)
                {
                    foreach (var child in spatialNode.children)
                    {
                        children[child.Key] = new SerializableSpatialNode(child.Value);
                    }
                }
            }
        }
    }
    
    /// <summary>
    /// 可序列化的短期记忆
    /// </summary>
    [System.Serializable]
    public class SerializableScratchMemory
    {
        public string agentName;
        public int age;
        public string personality;
        public string occupation;
        public string background;
        public DateTime currentTime;
        public SerializableVector3 currentLocation;
        public string currentLocationName;
        public string currentAction;
        public string mood;
        public float energy;
        public float socialBattery;
        public bool isInConversation;
        public string conversationPartner;
        public string conversationTopic;
        public string conversationId;
        public List<string> recentConversationPartners;
        public string currentPlanId;
        public DateTime lastPlanUpdate;
        public bool needsReplanning;
        public int importanceTriggerCurrent;
        public int importanceTriggerMax;
        public DateTime lastReflectionTime;
        public List<string> currentFocusPoints;
        public List<string> recentInsights;
        public List<string> currentlyPerceivedEvents;
        public List<string> recentlySeenAgents;
        public List<string> recentlySeenObjects;
        public DateTime lastPerceptionUpdate;
        public Dictionary<string, float> relationshipStates;
        public Dictionary<string, string> relationshipNotes;
        public List<string> closeFriends;
        public List<string> knownEnemies;
        public Dictionary<string, float> preferences;
        public List<string> habits;
        public List<string> goals;
        public List<string> fears;
        public Dictionary<string, object> workingMemory;
        public List<string> currentObservations;
        
        public SerializableScratchMemory() { }
        
        public SerializableScratchMemory(ScratchMemory scratchMemory)
        {
            if (scratchMemory != null)
            {
                agentName = scratchMemory.agentName;
                age = scratchMemory.age;
                personality = scratchMemory.personality;
                occupation = scratchMemory.occupation;
                background = scratchMemory.background;
                currentTime = scratchMemory.currentTime;
                currentLocation = new SerializableVector3(scratchMemory.currentLocation);
                currentLocationName = scratchMemory.currentLocationName;
                currentAction = scratchMemory.currentAction;
                mood = scratchMemory.mood;
                energy = scratchMemory.energy;
                socialBattery = scratchMemory.socialBattery;
                isInConversation = scratchMemory.isInConversation;
                conversationPartner = scratchMemory.conversationPartner;
                conversationTopic = scratchMemory.conversationTopic;
                conversationId = scratchMemory.conversationId;
                recentConversationPartners = new List<string>(scratchMemory.recentConversationPartners ?? new List<string>());
                currentPlanId = scratchMemory.currentPlanId;
                lastPlanUpdate = scratchMemory.lastPlanUpdate;
                needsReplanning = scratchMemory.needsReplanning;
                importanceTriggerCurrent = scratchMemory.importanceTriggerCurrent;
                importanceTriggerMax = scratchMemory.importanceTriggerMax;
                lastReflectionTime = scratchMemory.lastReflectionTime;
                currentFocusPoints = new List<string>(scratchMemory.currentFocusPoints ?? new List<string>());
                recentInsights = new List<string>(scratchMemory.recentInsights ?? new List<string>());
                currentlyPerceivedEvents = new List<string>(scratchMemory.currentlyPerceivedEvents ?? new List<string>());
                recentlySeenAgents = new List<string>(scratchMemory.recentlySeenAgents ?? new List<string>());
                recentlySeenObjects = new List<string>(scratchMemory.recentlySeenObjects ?? new List<string>());
                lastPerceptionUpdate = scratchMemory.lastPerceptionUpdate;
                relationshipStates = new Dictionary<string, float>(scratchMemory.relationshipStates ?? new Dictionary<string, float>());
                relationshipNotes = new Dictionary<string, string>(scratchMemory.relationshipNotes ?? new Dictionary<string, string>());
                closeFriends = new List<string>(scratchMemory.closeFriends ?? new List<string>());
                knownEnemies = new List<string>(scratchMemory.knownEnemies ?? new List<string>());
                preferences = new Dictionary<string, float>(scratchMemory.preferences ?? new Dictionary<string, float>());
                habits = new List<string>(scratchMemory.habits ?? new List<string>());
                goals = new List<string>(scratchMemory.goals ?? new List<string>());
                fears = new List<string>(scratchMemory.fears ?? new List<string>());
                workingMemory = new Dictionary<string, object>(scratchMemory.workingMemory ?? new Dictionary<string, object>());
                currentObservations = new List<string>(scratchMemory.currentObservations ?? new List<string>());
            }
        }
        
        public void RestoreTo(ScratchMemory scratchMemory)
        {
            if (scratchMemory == null) return;
            
            scratchMemory.agentName = agentName;
            scratchMemory.age = age;
            scratchMemory.personality = personality;
            scratchMemory.occupation = occupation;
            scratchMemory.background = background;
            scratchMemory.currentTime = currentTime;
            scratchMemory.currentLocation = currentLocation?.ToVector3() ?? Vector3.zero;
            scratchMemory.currentLocationName = currentLocationName;
            scratchMemory.currentAction = currentAction;
            scratchMemory.mood = mood;
            scratchMemory.energy = energy;
            scratchMemory.socialBattery = socialBattery;
            scratchMemory.isInConversation = isInConversation;
            scratchMemory.conversationPartner = conversationPartner;
            scratchMemory.conversationTopic = conversationTopic;
            scratchMemory.conversationId = conversationId;
            scratchMemory.recentConversationPartners = recentConversationPartners ?? new List<string>();
            scratchMemory.currentPlanId = currentPlanId;
            scratchMemory.lastPlanUpdate = lastPlanUpdate;
            scratchMemory.needsReplanning = needsReplanning;
            scratchMemory.importanceTriggerCurrent = importanceTriggerCurrent;
            scratchMemory.importanceTriggerMax = importanceTriggerMax;
            scratchMemory.lastReflectionTime = lastReflectionTime;
            scratchMemory.currentFocusPoints = currentFocusPoints ?? new List<string>();
            scratchMemory.recentInsights = recentInsights ?? new List<string>();
            scratchMemory.currentlyPerceivedEvents = currentlyPerceivedEvents ?? new List<string>();
            scratchMemory.recentlySeenAgents = recentlySeenAgents ?? new List<string>();
            scratchMemory.recentlySeenObjects = recentlySeenObjects ?? new List<string>();
            scratchMemory.lastPerceptionUpdate = lastPerceptionUpdate;
            scratchMemory.relationshipStates = relationshipStates ?? new Dictionary<string, float>();
            scratchMemory.relationshipNotes = relationshipNotes ?? new Dictionary<string, string>();
            scratchMemory.closeFriends = closeFriends ?? new List<string>();
            scratchMemory.knownEnemies = knownEnemies ?? new List<string>();
            scratchMemory.preferences = preferences ?? new Dictionary<string, float>();
            scratchMemory.habits = habits ?? new List<string>();
            scratchMemory.goals = goals ?? new List<string>();
            scratchMemory.fears = fears ?? new List<string>();
            scratchMemory.workingMemory = workingMemory ?? new Dictionary<string, object>();
            scratchMemory.currentObservations = currentObservations ?? new List<string>();
        }
    }
    
    /// <summary>
    /// 可序列化的Vector3
    /// </summary>
    [System.Serializable]
    public class SerializableVector3
    {
        public float x, y, z;
        
        public SerializableVector3() { }
        
        public SerializableVector3(Vector3 vector)
        {
            x = vector.x;
            y = vector.y;
            z = vector.z;
        }
        
        public Vector3 ToVector3()
        {
            return new Vector3(x, y, z);
        }
    }
    
    /// <summary>
    /// 可序列化的Quaternion
    /// </summary>
    [System.Serializable]
    public class SerializableQuaternion
    {
        public float x, y, z, w;
        
        public SerializableQuaternion() { }
        
        public SerializableQuaternion(Quaternion quaternion)
        {
            x = quaternion.x;
            y = quaternion.y;
            z = quaternion.z;
            w = quaternion.w;
        }
        
        public Quaternion ToQuaternion()
        {
            return new Quaternion(x, y, z, w);
        }
    }
}